package finance

import (
	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
	"likeadmin/admin/schemas/req"
	"likeadmin/admin/schemas/resp"
	"likeadmin/constant"
	"likeadmin/core/request"
	"likeadmin/core/response"
	"likeadmin/dao"
	"likeadmin/util"
	"math/rand"
	"strconv"
	"time"
)

type IRefundRecordService interface {
	List(c *gin.Context, page request.PageReq, listReq req.RefundRecordListReq) (res response.PageResp, e error)
	Stat(c *gin.Context) (resp resp.Stat, e error)
	GenerateSN(prefix string, randSuffixLength int) string
}

// NewRefundRecordService 初始化
func NewRefundRecordService(db *gorm.DB, dao *dao.Query) IRefundRecordService {
	return &refundRecordService{db: db, dao: dao}
}

// refundRecordService 退款记录服务实现类
type refundRecordService struct {
	db  *gorm.DB
	dao *dao.Query
}

// List 退款记录列表
func (srv refundRecordService) List(c *gin.Context, page request.PageReq, listReq req.RefundRecordListReq) (res response.PageResp, e error) {
	// 分页信息
	limit := page.PageSize
	offset := page.PageSize * (page.PageNo - 1)

	m := srv.dao.RefundRecord
	u := srv.dao.User
	q := m.WithContext(c)

	// 查询
	if listReq.Sn != "" {
		q = q.Where(m.Sn.Eq(listReq.Sn))
	}
	if listReq.OrderSn != "" {
		q = q.Where(m.OrderSn.Eq(listReq.OrderSn))
	}
	if listReq.UserSn > 0 {
		q = q.Where(m.UserSn.Eq(listReq.UserSn))
	}

	if listReq.RefundType > 0 {
		q = q.Where(m.RefundType.Eq(listReq.RefundType))
	}
	// listReq.RefundStatus 因没有传入值时也是0 所以前端传入10 表示全部
	if listReq.RefundStatus >= 0 && listReq.RefundStatus < 10 {
		q = q.Where(m.RefundStatus.Eq(listReq.RefundStatus))
	}

	// 时间范围查询
	if listReq.StartTime != "" && listReq.EndTime != "" {
		startTime, err := util.DateToTimestamp(listReq.StartTime)
		if e = response.CheckErr(err, "DateToTimestamp err"); e != nil {
			return
		}

		endTime, err := util.DateToTimestamp(listReq.EndTime)
		if e = response.CheckErr(err, "DateToTimestamp err"); e != nil {
			return
		}

		q = q.Where(m.CreateTime.Gt(int32(startTime)), m.CreateTime.Lt(int32(endTime)))
	}

	// 总数
	count, err := q.Count()
	if e = response.CheckErr(err, "List Count err"); e != nil {
		return
	}
	// 数据
	objs, err := q.Preload(m.User.Select(u.ID, u.Avatar, u.Nickname)).Limit(limit).Offset(offset).Order(m.ID.Desc()).Find()
	if e = response.CheckErr(err, "List Find err"); e != nil {
		return
	}
	var resps []resp.RefundRecordResp
	response.Copy(&resps, objs)

	for i, resp := range resps {
		resps[i].User.Avatar = util.UrlUtil.ToAbsoluteUrl(resp.User.Avatar)
		resps[i].RefundTypeText = constant.GetRefundTypeDesc(resp.RefundType)
		resps[i].RefundStatusText = constant.GetRefundStatusDesc(resp.RefundStatus)
	}

	return response.PageResp{
		PageNo:   page.PageNo,
		PageSize: page.PageSize,
		Count:    count,
		Lists:    resps,
	}, nil
}

// Stat 统计退款金额
func (srv refundRecordService) Stat(c *gin.Context) (resp resp.Stat, e error) {
	m := srv.dao.RefundRecord
	q := m.WithContext(c)

	//累计退款金额
	err := q.Select(m.OrderAmount.Sum().As("total")).Scan(&resp)
	if e = response.CheckErr(err, "List Count err"); e != nil {
		return
	}
	//累计退款中金额
	err = q.Where(m.RefundStatus.Eq(constant.RefundStatusRefunding)).Select(m.OrderAmount.Sum().As("ing")).Scan(&resp)
	if e = response.CheckErr(err, "List Count err"); e != nil {
		return
	}
	//累计已退款金额
	err = q.Where(m.RefundStatus.Eq(constant.RefundStatusRefunded)).Select(m.OrderAmount.Sum().As("success")).Scan(&resp)
	if e = response.CheckErr(err, "List Count err"); e != nil {
		return
	}
	//累计退款失败金额
	err = q.Where(m.RefundStatus.Eq(constant.RefundStatusFail)).Select(m.OrderAmount.Sum().As("error")).Scan(&resp)
	if e = response.CheckErr(err, "List Count err"); e != nil {
		return
	}

	return
}

// GenerateSN 生成随机单号
func (srv refundRecordService) GenerateSN(prefix string, randSuffixLength int) string {
	suffix := ""
	for i := 0; i < randSuffixLength; i++ {
		suffix += strconv.Itoa(rand.Intn(10))
	}

	sn := prefix + time.Now().Format("20060102150405") + suffix

	ua := srv.dao.RefundRecord
	_, err := ua.Where(ua.Sn.Eq(sn)).Select(ua.Sn).Take()
	if err == gorm.ErrRecordNotFound {
		return sn
	}
	return srv.GenerateSN(prefix, randSuffixLength)

}
